package cn.demoncat.util.oss.aliyun;

import cn.demoncat.util.exception.BizErrorRuntimeException;
import cn.demoncat.util.exception.BizRuntimeException;
import cn.demoncat.util.io.FileNameUtil;
import cn.demoncat.util.io.IoUtil;
import cn.demoncat.util.lang.ParamEmptyUtil;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.msg.FileMsg;
import cn.demoncat.util.oss.aliyun.config.AliyunOssProperties;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PutObjectResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * 阿里云 OSS 工具
 * 
 * @author 延晓磊
 *
 * @since 2019年11月11日
 */
@Component
public class AliyunOssUtil {

	private final AliyunOssProperties properties;
    private final OSSClient ossClient;

	/**
	 * 初始化
	 * 
	 * @param aliyunOssProperties
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	@Autowired
	public AliyunOssUtil(AliyunOssProperties aliyunOssProperties) {
		this.properties = aliyunOssProperties;
		// 校验参数
		ParamEmptyUtil.checkBlank(properties.getEndpoint(), properties.getKey(), properties.getSecret(), properties.getBucket(), properties.getDomain());
		// 创建OSS客户端
		this.ossClient = new OSSClient(properties.getEndpoint(), properties.getKey(), properties.getSecret());
	}
	
	/**
	 * 下载文件
	 * 
	 * @param fileUrl	文件地址：bucket/fileName
	 * 
	 * @return 文件
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public InputStream download(String fileUrl) {
		// 切割文件地址
		String[] arr = StringUtils.split(fileUrl, StringConstant.SEPARATOR, 2);
		// 下载
		return download(arr[0], arr[1]);	
	}
	
	/**
	 * 下载文件
	 * 
	 * @param bucket	存储空间
	 * @param fileName	文件名，前缀非/
	 * 
	 * @return 文件
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public InputStream download(String bucket, String fileName) {
		// 下载
		OSSObject result;
		try {
			result = ossClient.getObject(bucket, fileName);
		} catch (ClientException e) {
			throw new BizErrorRuntimeException("下载文件失败：" + e.getErrorMessage(), e);
		}
		// 结果校验
		if (!result.getResponse().isSuccessful()) {
			throw new BizRuntimeException("下载文件失败：" + result.getResponse().getErrorResponseAsString());
		}
		// 读取结果
		return result.getObjectContent();
	}
	
	/**
	 * 下载文件
	 * 
	 * @param bucket	存储空间
	 * @param fileName	文件名，前缀非/
	 * @param out		输出流（未关闭）
	 * 
	 * @return 文件
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public void download(String bucket, String fileName, OutputStream out) {
		try {
			IoUtil.copy(download(bucket, fileName), out);
		}catch (Exception e) {
			throw new BizErrorRuntimeException(FileMsg.DOWNLOAD_FILE_ERROR, e);
		}
	}
	
	/**
	 * 删除文件
	 * 
	 * @param fileUrl	文件地址：bucket/fileName
	 * 
	 * @return 文件地址
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public void delete(String fileUrl) {
		// 切割文件地址
		String[] arr = StringUtils.split(fileUrl, StringConstant.SEPARATOR, 2);
		// 删除
		delete(arr[0], arr[1]);	
	}
	
	/**
	 * 删除文件
	 * 
	 * @param bucket	存储空间
	 * @param fileName	文件名，前缀非/
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public void delete(String bucket, String fileName) {
		// 删除
		try {
			ossClient.deleteObject(bucket, fileName);
		} catch (ClientException e) {
			throw new BizErrorRuntimeException("删除文件失败：" + e.getErrorMessage(), e);
		}
	}
	
	/**
	 * 列表文件
	 * 
	 * @param filePre	文件名前缀，前缀非/
	 * @return 文件列表
	 * 
	 * @author 延晓磊
	 * @return 
	 *
	 * @since 2019年11月11日
	 */
	public List<OSSObjectSummary> list(String filePre) {
		// 列表文件
		ObjectListing result;
		try {
			if (StringUtils.isBlank(filePre)) {
				result = ossClient.listObjects(properties.getBucket());
			}else {
				result = ossClient.listObjects(properties.getBucket(), filePre);
			}
		} catch (ClientException e) {
			throw new BizErrorRuntimeException("查看文件失败：" + e.getErrorMessage(), e);
		}
		// 结果校验
		if (!result.getResponse().isSuccessful()) {
			throw new BizRuntimeException("查看文件失败：" + result.getResponse().getErrorResponseAsString());
		}
		// 文件列表
		return result.getObjectSummaries();
	}
	
	/**
	 * 上传文件
	 * 
	 * @param fileName	文件名，前缀非/
	 * @param in		文件
	 * 
	 * @return 文件地址：bucket/fileName
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public String upload(String fileName, InputStream in) {
		// 上传
		PutObjectResult result;
		try {
			result = ossClient.putObject(properties.getBucket(), fileName, in);
		} catch (ClientException e) {
			throw new BizErrorRuntimeException("上传文件失败：" + e.getErrorMessage(), e);
		}
		// 结果校验
		if (!result.getResponse().isSuccessful()) {
			throw new BizRuntimeException("上传文件失败：" + result.getResponse().getErrorResponseAsString());
		}
		// 返回URL
		return properties.getBucket() + StringConstant.SEPARATOR + fileName;
	}

	/**
	 * 上传文件
	 *
	 * @param file
	 *
	 * @return 文件地址：bucket/fileName
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public String upload(MultipartFile file) {
		try {
			return upload(FileNameUtil.getRandomName(file.getOriginalFilename()), file.getInputStream()) + StringConstant.HASH + file.getOriginalFilename();
		} catch (IOException e) {
			throw new BizRuntimeException("上传文件失败：读取文件失败", e);
		}
	}

	/**
	 * 获取文件地址
	 *
	 * @param name
	 *
	 * @return 文件地址：http://url/name
	 *
	 * @author 延晓磊
	 * @since 2022年07月11日
	 */
	public String url(String name){
		return "http://" + properties.getDomain() + "/" + name;
	}

	/**
	 * 获取文件地址
	 *
	 * @param name
	 *
	 * @return 文件地址：https://url/name
	 *
	 * @author 延晓磊
	 * @since 2022年07月11日
	 */
	public String urls(String name){
		return "https://" + properties.getDomain() + "/" + name;
	}
}
